import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
} from '@nestjs/common';
import { Response } from 'express';
import { getExceptionByStatusCode, sendExceptionResponse } from 'src/utils';

/**
 * 捕获系统所有的http异常,http异常有代码主动抛出，例如throw new HttpException,throw new BadRequestException ....
 */
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    // 获取http状态码
    const statusCode = exception.getStatus();
    // 获取错误内容实体,实体有可能是字符串，比如throw new HttpException('this is message',400)
    // 也有可能是对象{error:xxx,message:xxx},比如throw new HttpException({error:xxx,message:xxx},400)，throw new BadRequestException('xxx')
    const errorResponse = exception.getResponse();
    //如果是字符串
    if (typeof errorResponse === 'string') {
      const errorName = getExceptionByStatusCode(statusCode).error;
      sendExceptionResponse({
        response,
        statusCode,
        errorName,
        message: errorResponse,
        detail: null,
        exception,
      });
    }
    // 否则，errorResponse是对象
    else {
      //通过statusCode获取标准的http error名称，比如Not Found ,Conflict ...
      const errorName = getExceptionByStatusCode(statusCode).error;
      // 如果有自定义的detail，获取
      const detail = errorResponse['detail'] || null;
      // originalErrorToLog用于处理当代码中抛出throw new HttpException({message:xxx,originalErrorToLog:error})时,log日志记录最原始的的错误
      const originalErrorToLog = errorResponse['originalErrorToLog'];
      //当有原始错误时，写入log的异常为原始错误，否则，使用最简单的http 错误
      const sendExceptionError = originalErrorToLog
        ? originalErrorToLog
        : exception;
      const message = errorResponse['message'];
      const showMessage = Array.isArray(message) ? message[0] : message; //message如果是数组，取第一个
      sendExceptionResponse({
        response,
        statusCode,
        errorName,
        message: showMessage,
        detail: detail,
        exception: sendExceptionError,
      });
    }
  }
}
